/**
 * @class Spark
 * Spark 核心类.
 * @author 牛佳庆
 * @singleton
 */
$S = Spark = {version: '1.0'};
$S.fireWindowResize = function(){
    $S.Cover.resizeCover();
}
Ext.EventManager.on(window, "resize", $S.fireWindowResize, this);
Ext.EventManager.on(document, "mousewheel", function(e){
    if(e.ctrlKey)e.preventDefault();
    //Where is the "Ctrl + mouse wheel" page size adjustment reset button?  ctrl + 0 
}, this);


$S.cache = {};
$S.cmps = {};
$S.onReady = function(fn, scope, options){
    if(window['__host']){
        if(!$S.loadEvent)$S.loadEvent = new Ext.util.Event();
        $S.loadEvent.addListener(fn, scope, options);
    }else{
        Ext.onReady(fn, scope, options);
    }
}

$S.get = Ext.get;
$S.defaultDateFormat='isoDate';
$S.defaultDateTimeFormat="yyyy-mm-dd HH:MM:ss";
$S.defaultChineseLength = 2;

$S.viewHeight = 768;
$S.viewWidth = 1024;
$S.suk = null;



$S.system = function(){
    var l = arguments.length;
    if(l==1){
        if($S._system){
            return $S._system[arguments[0]]
        }
    }else if(l==2){
        if(!$S.system) $S._system = {};
        $S._system[arguments[0]] = arguments[1]
    }
}
$S.center = function(el){
    var ele;
    if(typeof(el)=="string"){
        var cmp = $S.CmpManager.get(el)
        if(cmp){
            if(cmp.wrap){
                ele = cmp.wrap;
            }
        }else{
             ele = Ext.get(el);
        }             
    }else{
        ele = Ext.get(el);
    }
    var screenWidth = $S.getViewportWidth();
    var screenHeight = $S.getViewportHeight();
    var x = Math.max(0,(screenWidth - ele.getWidth())/2);
    var y = Math.max(0,(screenHeight - ele.getHeight())/2);
    ele.setStyle('position','absolute');
    ele.moveTo(x,y);
}

$S.CmpManager = function(){
    return {
        put : function(id, cmp){
            if(window['__host']&&window['__host'].cmps)window['__host'].cmps[id] = cmp;
            if(!this.cache) this.cache = {};
            if(this.cache[id] != null) {
                alert("Error: Componet '" + id +"' already exists!");
                return;
            }
            this.cache[id]=cmp;
//            cmp.on('mouseover',$S.CmpManager.onCmpOver,$S.CmpManager);
//            cmp.on('mouseout',$S.CmpManager.onCmpOut,$S.CmpManager);
        },
//        onCmpOver: function(cmp, e){
//            if(cmp.binder){
//                var ds = cmp.binder.ds;
//                if(!ds)return;
//                var record = cmp.record;
//                if(!record)return;
//                var field = record.getField(cmp.binder.name)
//                var msg = record.valid[cmp.binder.name] || field.get('tooltip');                
//                if(Ext.isEmpty(msg))return;
//                $S.ToolTip.show(cmp.wrap, msg);
//            }
//        },
//        onCmpOut: function(cmp,e){
//            if(cmp.binder)
//            $S.ToolTip.hide();
//        },
        getAll : function(){
            return this.cache;
        },
        remove : function(id){
            var cmp = this.cache[id];
            if(cmp) {
                if(cmp['__host'] && cmp['__host'].cmps){
                    delete cmp['__host'].cmps[id];        
                }
                cmp.un('mouseover',$S.CmpManager.onCmpOver,$S.CmpManager);
                cmp.un('mouseout',$S.CmpManager.onCmpOut,$S.CmpManager);
                delete this.cache[id];
            }
        },
        get : function(id){
            if(!this.cache) return null;
            return this.cache[id];
        }
    };
}();
Ext.Ajax.on("requestexception", function(conn, response, options) {
    if(options.longpolling) return;
    $S.EM.fireEvent('ajaxerror', $S.EM, response.status, response);
    if(response.isTimeout) {
        $S.showErrorMessage('错误', "网络超时!");
        return;
    }
    switch(response.status){
        case 404:
            $S.showErrorMessage('404 Error', response.statusText,null,400,150);
            break;
        case 500:
            $S.showErrorMessage(response.status + ' Error', response.responseText,null,800,600);
            break;
        default:
            $S.showErrorMessage('Error', response.statusText);
            break;
    }   
}, this);
$ = $S.getCmp = function(id){
    var cmp = $S.CmpManager.get(id)
    return cmp;
}
$S.equals = function(v1,v2){
    if(v1 === v2 || (Ext.isEmpty(v1,false)&&Ext.isEmpty(v2,false)))return true;
    if(Ext.isDate(v1) && Ext.isDate(v2)){
        if(v1.xtype=='datetime' && v2.xtype=='datetime') {
            return v1.getTime() == v2.getTime();
        }else{
            return v1.getFullYear()==v2.getFullYear() && v1.getMonth() == v2.getMonth() && v1.getDate() == v2.getDate();        
        }
    }
    return false;
}
$S.setCookie = function(name,value){
    var pathname = location.pathname;
    pathname = pathname.substring(0, pathname.lastIndexOf('/'));
    document.cookie = name + "="+ escape (value) +';path = ' + pathname;
}
$S.getCookie = function(name){
    var arr = document.cookie.match(new RegExp("(^| )"+name+"=([^;]*)(;|$)"));
    if(arr != null) return unescape(arr[2]); return null;

}
$S.getViewportHeight = function(){
    if(Ext.isIE){
        return Ext.isStrict ? document.documentElement.clientHeight :
                 document.body.clientHeight;
    }else{
        return self.innerHeight;
    }
}
$S.getViewportWidth = function() {
    if(Ext.isIE){
        return Ext.isStrict ? document.documentElement.clientWidth :
                 document.body.clientWidth;
    }else{
        return self.innerWidth;
    }
}
$S.post = function(action,data){
    var form = Ext.getBody().createChild({tag:'form',method:'post',action:action});
    for(var key in data){
        if(data[key])
        form.createChild({tag:"input",type:"hidden",name:key,value:data[key]});
    }
    form.dom.submit();
}
$S.request = function(opt){
    var url = opt.url,para = opt.para,successCall = opt.success,errorCall = opt.error,scope = opt.scope,failureCall = opt.failure;
    var opts = Ext.apply({},opt.opts);
    $S.EM.fireEvent('ajaxstart', url, para);
    return Ext.Ajax.request({
        url: url,
        method: 'POST',
        params:{SUK:$S.suk,_sph:$S.viewHeight,_spw:$S.viewWidth,_request_data:Ext.util.JSON.encode({parameter:para})},
        opts:opts,
        success: function(response,options){
            $S.EM.fireEvent('ajaxcomplete', url, para,response);
            if(response){
                var res = null;
                try {
                    res = Ext.decode(response.responseText);
                }catch(e){}
                if(res){
                    if(res.success){//成功
                        $S.EM.fireEvent('ajaxsuccess', $S.EM, url,para,res);
                        if(successCall)successCall.call(scope,res, options);
                    }else{//失败
                        $S.EM.fireEvent('ajaxfailed', $S.EM, url,para,res);
                        var w = res.width||400,h = res.height||250;
                        var msg = res.message||'';
                        if(res.failedType == 'error'){
                            $S.showErrorMessage(res.title||'错误', msg,null,w,h);
                        }else if(res.failedType == 'warning'){
                            $S.showWarningMessage(res.title||'警告', msg,null,w,h);
                        }else if(res.failedType == 'info'){
                            $S.showInfoMessage(res.title||'提示', msg,null,w,h);
                        }else if(res.failedType == 'sessionTimeout'){
                            $S.EM.fireEvent('sessionTimeout');
                        }
                        if(errorCall)errorCall.call(scope, res, options);  
                    }
                }else{
                    $S.showErrorMessage('系统错误', '返回格式不正确!');
                    if(errorCall)errorCall.call(scope, null, options);
                }
//              if(res && !res.success){
//                  $S.EM.fireEvent('ajaxfailed', $S.EM, url,para,res);
//                  if(res.error){
//                      var st = res.error.stackTrace;
//                      st = (st) ? st.replaceAll('\r\n','</br>') : '';
//                      if(res.error.message) {
//                          var h = (st=='') ? 150 : 250;
//                          $S.showErrorMessage('Error', res.error.message+'</br>'+st,null,400,h);
//                      }else{
//                          $S.showErrorMessage('Error', st,null,400,250);
//                      }
//                      if(errorCall)
//                        errorCall.call(scope, res, options);  
//                  }                                                               
//              } else {
//                  $S.EM.fireEvent('ajaxsuccess', $S.EM, url,para,res);
//                  if(successCall)successCall.call(scope,res, options);
//              }
            }
        },
        failure : function(response, options){
            if(failureCall)failureCall.call(scope, response, options);
        },
        scope: scope
    });
}

$S.dateFormat = function () { 
    var masks = {  
        "default":      "ddd mmm dd yyyy HH:MM:ss",  
        shortDate:      "m/d/yy",  
        mediumDate:     "mmm d, yyyy",  
        longDate:       "mmmm d, yyyy",  
        fullDate:       "dddd, mmmm d, yyyy",  
        shortTime:      "h:MM TT",  
        mediumTime:     "h:MM:ss TT",  
        longTime:       "h:MM:ss TT Z",  
        isoDate:        "yyyy-mm-dd",  
        isoTime:        "HH:MM:ss",  
        isoDateTime:    "yyyy-mm-dd HH:MM:ss", // "yyyy-mm-dd'T'HH:MM:ss",  
        isoUtcDateTime: "UTC:yyyy-mm-dd HH:MM:ss'Z'"  //"UTC:yyyy-mm-dd'T'HH:MM:ss'Z'" 
    };
    var token = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloSZ]|"[^"]*"|'[^']*'/g,  
        timezone = /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g,  
        timezoneClip = /[^-+\dA-Z]/g,  
        pad = function (val, len) {  
            val = String(val);  
            len = len || 2;  
            while (val.length < len) val = "0" + val;  
            return val;  
        },
        hasTimeStamp = function(mask,token){
            return !!String(masks[mask] || mask || masks["default"]).match(token);
        },
        _parseDate=function(s,mask,fun){
            if(!s)return s;
            for(var i=0,arr=mask.match(token),numbers=s.match(/\d+/g),value;i<arr.length;i++){
                if(numbers.length==arr.length)value=numbers[i];
                else value=parseInt(s.slice(index=mask.search(arr[i]),index+arr[i].length));
                switch(arr[i]){
                    case "mm":;
                    case "m":value=value-1;break;
                }
                fun(arr[i],value);
            }
        }; 
    return {
        pad:pad,
        parseDate:function(string,mask,utc){
            if(typeof string!="string"||string=="")return null;
            mask = String(masks[mask] || mask || masks["default"]); 
            if (mask.slice(0, 4) == "UTC:") {  
                mask = mask.slice(4);  
                utc = true;  
            }
            var date=new Date(1970,1,2,0,0,0),
                _ = utc ? "setUTC" : "set",  
                d = date[_ + "Date"],  
                m = date[_ + "Month"],  
                yy = date[_ + "FullYear"], 
                y = date[_ + "Year"], 
                H = date[_ + "Hours"],  
                M = date[_ + "Minutes"],  
                s = date[_ + "Seconds"],  
                L = date[_ + "Milliseconds"],  
                //o = utc ? 0 : date.getTimezoneOffset();
                flags = {  
                    d:    d,  
                    dd:   d,
                    m:    m,  
                    mm:   m,  
                    yy:   y,  
                    yyyy: yy,  
                    h:    H,  
                    hh:   H,  
                    H:    H,  
                    HH:   H,  
                    M:    M,  
                    MM:   M,  
                    s:    s,  
                    ss:   s,  
                    l:    L,  
                    L:    L
                }; 
                try{
                    _parseDate(string,mask,function($0,value){
                        if(flags[$0])flags[$0].call(date,value);
                    });
                }catch(e){throw new SyntaxError("invalid date");}
                if (isNaN(date)) throw new SyntaxError("invalid date"); 
                return date;
        },
        format:function (date, mask, utc) {    
            if (arguments.length == 1 && (typeof date == "string" || date instanceof String) && !/\d/.test(date)) {  
                mask = date;  
                date = undefined;  
            }   
            date = date ? new Date(date) : new Date();  
            if (isNaN(date)) throw new SyntaxError("invalid date");  
      
            mask = String(masks[mask] || mask || masks["default"]);  
            if (mask.slice(0, 4) == "UTC:") {  
                mask = mask.slice(4);  
                utc = true;  
            }  
      
            var _ = utc ? "getUTC" : "get",  
                d = date[_ + "Date"](),  
                D = date[_ + "Day"](),  
                m = date[_ + "Month"](),  
                y = date[_ + "FullYear"](),  
                H = date[_ + "Hours"](),  
                M = date[_ + "Minutes"](),  
                s = date[_ + "Seconds"](),  
                L = date[_ + "Milliseconds"](),  
                o = utc ? 0 : date.getTimezoneOffset(),  
                flags = {  
                    d:    d,  
                    dd:   pad(d),
                    m:    m + 1,  
                    mm:   pad(m + 1),  
                    yy:   String(y).slice(2),  
                    yyyy: y,  
                    h:    H % 12 || 12,  
                    hh:   pad(H % 12 || 12),  
                    H:    H,  
                    HH:   pad(H),  
                    M:    M,  
                    MM:   pad(M),  
                    s:    s,  
                    ss:   pad(s),  
                    l:    pad(L, 3),  
                    L:    pad(L > 99 ? Math.round(L / 10) : L),  
                    t:    H < 12 ? "a"  : "p",  
                    tt:   H < 12 ? "am" : "pm",  
                    T:    H < 12 ? "A"  : "P",  
                    TT:   H < 12 ? "AM" : "PM",  
                    Z:    utc ? "UTC" : (String(date).match(timezone) || [""]).pop().replace(timezoneClip, ""),  
                    o:    (o > 0 ? "-" : "+") + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4),  
                    S:    ["th", "st", "nd", "rd"][d % 10 > 3 ? 0 : (d % 100 - d % 10 != 10) * d % 10]  
                }; 
            return mask.replace(token, function ($0) {  
                return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1);  
            });  
        },
        isDateTime:function(mask){
            return hasTimeStamp(mask,/([HhMs])\1?/);
        }
    };  
}();

Ext.applyIf(String.prototype, {
    trim : function(){
        return this.replace(/(^\s*)|(\s*$)/g, "");
    },
    replaceAll : function(s1,s2){
        return this.replace(new RegExp(s1,"gm"),s2);  
    },
    parseDate : function(mask,utc){
        return $S.dateFormat.parseDate(this.toString(),mask,utc);  
    }
});
Ext.applyIf(Date.prototype, {
    format : function(mask, utc){
        return $S.dateFormat.format(this, mask, utc);  
    },
    isSame : function(d){
        if(!this.getFullYear||!d.getFullYear)return false;
        return (this.getFullYear() == d.getFullYear() && this.getMonth() == d.getMonth() && this.getDate() == d.getDate());
    }
});
Ext.applyIf(Array.prototype, {
    add : function(o){
        if(this.indexOf(o) == -1)
        this[this.length] = o;
    },
    find : function(n,v){
        for(var i = 0, len = this.length; i < len; i++){
            var o = this[i];
            if(o[n] == v) return o
        }
        return null;
    }
});
$S.TextMetrics = function(){
    return {
        measure : function(text){
            var shared = $S.TextMetrics.Instance();
            return shared.getSize(text);
        }
    };
}();
$S.TextMetrics.Instance = function(){
    var p = '<div style="left:-10000px;top:-10000px;position:absolute;visibility:hidden"></div>';
    if(!$S.TextMetrics.obj) {
        $S.TextMetrics.obj = Ext.DomHelper.append(Ext.get(document.body),p)
    }
    var ml = Ext.get($S.TextMetrics.obj);
    var instance = {      
        getSize : function(text){
            ml.update(text);            
            var s=new Object();
            s.width=ml.getWidth();
            s.height=ml.getHeight();
            ml.update('');
            return s;
        },       
        bind : function(el){
            var a=new Array('font-size','font-style', 'font-weight', 'font-family','line-height', 'text-transform', 'letter-spacing');  
            var len = a.length, r = {};
            for(var i = 0; i < len; i++){
                r[a[i]] = Ext.fly(el).getStyle(a[i]);
            }
            ml.setStyle(r);           
        },       
        setFixedWidth : function(width){
            ml.setWidth(width);
        }       
    };
    instance.bind(document.body);
    return instance;
};

$S.DocMg = function(){
    var me = {
        handlers : [],
        init: function(){
            Ext.each(this.handlers,function(h){
                if(h.init) h.init();
            },this)
            Ext.get(document.documentElement).on("mouseover", this.onDocMouseOver, this);
            Ext.get(document.documentElement).on("mousedown", this.onDocMouseDown, this);
        },
        onDocMouseOver : function(e){
            Ext.each(this.handlers,function(h){
                if(h.onMouseOver) h.onMouseOver(e);
            },this)
        },
        onDocMouseDown : function(e){
            Ext.each(this.handlers,function(h){
                if(h.onMouseDown) h.onMouseDown(e);
            },this)
        },
        register : function(h){
            this.handlers.push(h);
        }
    }
    Ext.onReady(function(){
        me.init();
    });
    return me;
}();
//$S.Tip = function(){
//    var tip = {
//        el:null,
//        styles:{},
////        fa: new Array('height','line-height'), 
//        fa: new Array('text-overflow','overflow', 'position', 'z-index', 'max-width','width','height','line-height'), 
//        hide: function(){;
//            if(this.el){
//                this.el.removeClass('s-tip');
//                //this.el.parent().setStyle({'position':'static'});
//                this.el.setStyle(this.styles);
//                this.styles = {};
////                this.el.setStyle({
////                    'text-overflow' : 'ellipsis',
////                    'overflow':'hidden',
////                    'position': 'absolute',
////                    'z-index':''
////                });
//                this.el = null;
//            }
//        },
//        show: function(t){
//            this.el = t;
//            var isTip = Ext.fly(t).getAttributeNS('','tip');
//            if(isTip == '') return;
//            var r={},text = t.dom.innerHTML,ew = t.getWidth(),tw = $S.TextMetrics.measure(text),dbody = document[Ext.isStrict&&!Ext.isWebKit?'documentElement':'body'], sh=$S.getViewportHeight(),sw=$S.getViewportWidth(),
//                sl = dbody.scrollLeft,st = dbody.scrollTop,tx = t.getX() - sl,ty = t.getY() - st;
//            if(tw.width > ew){
//                for(var i = 0; i < this.fa.length; i++){
//                    this.styles[this.fa[i]] = Ext.fly(t).getStyle(this.fa[i]);
//                }
//                var tb = Ext.fly(t).getBorderWidth('t'),bb = Ext.fly(t).getBorderWidth('b');
//                var h = Ext.fly(t).getHeight()-tb-bb;
//                this.el.addClass('s-tip');
//                this.el.setStyle({
//                    'text-overflow' : 'clip',
//                    'overflow':'visible',
//                    'position': 'absolute',
//                    'line-height':h+'px',
//                    'height':h+'px',
//                    'width':'auto',
//                    'max-width' : 'none',
//                    'z-index':99999
//                });
//                //this.el.parent().setStyle({'position':'relative'})
//                this.el.setX(tx-1);
//                this.el.setY(ty-1);
//            }
//        },
//        findTarget: function(e){
//            var tg = Ext.get(e.target);
//            var t = tg.getAttributeNS('','tip');
//            if(t=='true'){ 
//                return tg;
//            }
//        },
//        onMouseDown: function(e){
//            this.hide();
//        },
//        onMouseOver: function(e){
//            e.stopEvent();
//            var sf = this;
//            if(sf.el && sf.el.contains(e.target)) {
//                return;
//            }
//            var tg = sf.findTarget(e);
//            sf.hide();
//            if(tg) sf.show(tg);
//        }
//    }
//    $S.DocMg.register(tip);
//    return tip
//}();
$S.Tip = function(){
    var tip = {
        el:null, 
        tpl:'<div class="s-tip" style=""background-color:#ededed;Z-INDEX: 99999; POSITION:absolute; left:0px;top:0px;white-space:nowrap;LINE-HEIGHT: 30px; WIDTH: auto; TEXT-OVERFLOW: clip; MAX-WIDTH: none; HEIGHT: 30px; OVERFLOW: visible;"></div>',
        fa: new Array('font-size','text-indent', 'font-style', 'font-weight', 'font-family','line-height', 'letter-spacing','padding-right'),  
        init: function(){
            var p = '<div class="s-tip"></div>';
            this.el = Ext.get(Ext.DomHelper.insertFirst(Ext.getBody(),p));            
        },
        hide: function(){           
            this.el.dom.style.display = 'none';
            var p = this.el.parent('.grid-cell');
            if(p) p.removeClass('s-tip-parent');
            Ext.getBody().appendChild(this.el);
        },
        show: function(t){
            var isTip = Ext.fly(t).getAttributeNS('','tip');
            if(isTip == '') return;
            var pr={}, r={},text = t.dom.innerHTML,ew = t.getWidth(),tw = $S.TextMetrics.measure(text);
            if(tw.width+10 > ew){//text-indent + padding-right = 10
                var dbody = document[Ext.isStrict&&!Ext.isWebKit?'documentElement':'body'], sh=$S.getViewportHeight(),sw=$S.getViewportWidth(),
                sl = dbody.scrollLeft,st = dbody.scrollTop,tx = t.getX() - sl,ty = t.getY() - st;
                this.el.update(text);
                this.el.setHeight(t.getHeight()-1);
                for(var i = 0; i < this.fa.length; i++){
                    r[this.fa[i]] = Ext.fly(t).getStyle(this.fa[i]);
                }
                r['line-height'] = t.getHeight() + 'px';
                var p = this.el.parent('.grid-cell');
                if(p) p.removeClass('s-tip-parent');
                this.el.setStyle(r);
                Ext.fly(t).appendChild(this.el);
                this.el.parent('.grid-cell').addClass('s-tip-parent');
                this.el.dom.style.display = 'block';
            }
        },
        findTarget: function(e){
            var tg = Ext.get(e.target);
            var t = tg.getAttributeNS('','tip');
            return t == '' ? null : tg;
        },
        onMouseDown: function(e){
            this.hide();
        },
        onMouseOver: function(e){
            e.stopEvent();
            var sf = this;
            if(sf.el && sf.el.contains(e.target)) {
                return;
            }
            var tg = sf.findTarget(e);
            sf.hide();
            if(tg){
                sf.show(tg);
            }
        }
    }
    $S.DocMg.register(tip);
    return tip
}();
$S.ToolTip = function(){
    var tip = {
        dt:'data-tooltip',
        hid:null,
        el:null,
        crt:null,
        ecs: ['s-bubble-promo','s-bubble-black','s-bubble-valid'],
        ars : ['s-bubble-arrowdown','s-bubble-arrowup','s-bubble-arrowleft','s-bubble-arrowright'],       
        init: function(){
            var p = '<div class="s-bubble" ><div class="s-bubble-content-id"></div><div class="s-bubble-arrow-id s-bubble-arrow"><div class="s-bubble-arrowimplbefore"></div><div class="s-bubble-arrowimplafter"></div></div></div>';
            this.el = Ext.get(Ext.DomHelper.insertFirst(Ext.getBody(),p));
        },
        hide: function(){
            this.crt = null;
            this.el.moveTo(-10000,-10000);
            this.el.dom.style.opacity = 0;
        },
        getPosition : function(align){
            return {
                isT : align.indexOf('t') == 0,
                isTL : align.indexOf('tl') !== -1,
                isTR : align.indexOf('tr') !== -1,
                isB : align.indexOf('b') == 0,
                isBL : align.indexOf('bl') !== -1,
                isBR : align.indexOf('br') !== -1,
                isL : align.indexOf('l') == 0,
                isLT : align.indexOf('lt') !== -1,
                isLB : align.indexOf('lb') !== -1,
                isR : align.indexOf('r') ==0,
                isRT : align.indexOf('rt') !== -1,
                isRB : align.indexOf('rb') !== -1
            }
        },
        restrict : function(t){
            var type = Ext.fly(t).getAttributeNS('',this.dt + '-type'), margin = type=='tip' ? 2 : 10,tip = this.el,ar = tip.child('div.s-bubble-arrow'),align = Ext.fly(t).getAttributeNS('',this.dt + '-align'),align = align ? align : 'b',
                dbody = document[Ext.isStrict&&!Ext.isWebKit?'documentElement':'body'], sh=$S.getViewportHeight(),sw=$S.getViewportWidth(),
                sl = dbody.scrollLeft,st = dbody.scrollTop,tw = t.getWidth(),th = t.getHeight(),tph = tip.getHeight(),
                tpw = tip.getWidth(),tx = t.getX() - sl,ty = t.getY() - st,ap = this.getPosition(align),p1=align.substring(0,1),p2=align.substring(1,2);
                if(ap.isT||ap.isB) {
                    if(ty - tph - margin <=0){
                        p1 = 'b';
                    }else if(ty + th + tph + margin >sh){
                        p1 = 't';
                    }
                    if((ap.isTR||ap.isBR) && tx + tpw > sw) {
                        p2= 'l';
                    }else if((ap.isTL||ap.isBL) && tx + tpw - tpw <=0) {
                        p2= 'r';
                    }else if(((!ap.isTL && !ap.isTR)||(!ap.isBL && !ap.isBR)) && tx + tw/2 + tpw/2 > sw) {
                        p2= 'l';
                    }else if(((!ap.isTL && !ap.isTR)||(!ap.isBL && !ap.isBR)) && tx + tw/2 - tpw/2 <=0) {
                        p2= 'r';
                    }else if(tpw<tw){
                        p2='';
                    }
                }
                if(ap.isL||ap.isR) {
                    if(tx + tw + tpw + margin > sw) {
                        p1= 'l';
                    } else if(tx - tpw - margin <=0) {
                        p1= 'r';
                    }
                    if((ap.isLT||ap.isRT) && ty + th - tph<=0){
                        p2 = 'b';
                    }else if((ap.isLB||ap.isRB) && ty + tph>sh){
                        p2 = 't';
                    }else if(((!ap.isLT && !ap.isLB)||(!ap.isRT && !ap.isRB)) && ty + th/2 + tph/2 > sh) {
                        p2= 't';
                    }else if(((!ap.isLT && !ap.isLB)||(!ap.isRT && !ap.isRB)) && ty + th/2 - tph/2 <=0) {
                        p2= 'b';
                    }else if(tph<th){
                        p2='';
                    }
                }
                var x,y,at,al,p = p1+p2,arcs,ap2 = this.getPosition(p);
                if(ap2.isT||ap2.isB){
                    arcs = ap2.isT ? this.ars[0] : this.ars[1];
                    if(p=='t'||p=='b'){
                        x = tx + (tw-tpw)/2;
                        al = tpw/2;
                    }else if(ap2.isTR||ap2.isBR){
                        x = tx;
                        al = tw/2;
                    }else if(ap2.isTL||ap2.isBL){
                        x = tx + tw - tpw; 
                        al = tpw-tw/2;
                    }
                    y = ap2.isT ? ty - tph - margin : ty + th + margin;
                }else if(ap2.isL||ap2.isR){
                    arcs = ap2.isL ? this.ars[3] : this.ars[2];
                    if(p=='l'||p=='r'){
                        y = ty + (th-tph)/2;
                        at = tph/2;
                    }else if(ap2.isLB||ap2.isRB){
                        y = ty;
                        at = th/2;
                    }else if(ap2.isLT||ap2.isRT){
                        y = ty + th - tph; 
                        at = tph - th/2;
                    }
                    x = ap2.isL ? tx - tpw - margin : tx + tw + margin;
                }
                tip.setX(x + sl).setY(y + st);
                ar.removeClass(this.ars).addClass(arcs);
                ar.setStyle('left',null).setStyle('top',null);
                (ap2.isT||ap2.isB) ? ar.setStyle('left',al+'px'): ar.setStyle('top',at+'px');
                
        },
        show: function(t){
            if(t&&!Ext.fly(t).hasClass('s-btn-disabled')) {
                if(this.crt == t) return;
                this.crt = t;
                var tip = this.el, text = Ext.fly(t).getAttributeNS('',this.dt),
                    style = Ext.fly(t).getAttributeNS('',this.dt + '-style'), type = Ext.fly(t).getAttributeNS('',this.dt + '-type'),style = (style==''&&type == 'tip') ? 'black': style;
                if(text == '') return;
                if(text.indexOf('call:')==0){
                    var fn = $S.getFunction(text.substring(5,text.length));                
                    if(fn != null) text = fn.call(window, t);                  
                }
                               
                this.el.removeClass(this.ecs);
                this.el.removeClass('s-bubble-tip');
                if(type=='tip') this.el.addClass('s-bubble-tip');
                if(style) this.el.addClass('s-bubble-'+style);
                tip.child('.s-bubble-content-id').update(text);  
                this.restrict(t);
                tip.dom.style.opacity = 1;
            }
        },
        findTarget: function(e){
            var tg = Ext.get(e.target);
            var t = tg.getAttributeNS('',this.dt);
            if(t == ''){
                tg = tg.parent('['+this.dt+']');
                if(tg) t = tg.getAttributeNS('',this.dt);
            }
            return t == '' ? null : tg;
        },
        clear: function(){
            var sf = this;
            if(sf.hid) {
                clearTimeout(sf.hid);
                sf.hid = null;
            }
            if(sf.sid) {
                clearTimeout(sf.sid);
                sf.sid = null;
            }
        },
        onMouseDown: function(e){
            var sf = this;
            var tg = sf.findTarget(e);
            if(tg != null && tg.contains(e.target)){
                sf.clear();
                sf.hide();
                return;
            }
        },
        onMouseOver: function(e){
            e.stopEvent();
            var sf = this;
            if(sf.el.contains(e.target)) {
                if(sf.hid) {
                    clearTimeout(sf.hid);
                    sf.hid = null;
                }
                return;
            }
            var tg = sf.findTarget(e);
            if(tg == null){
                if(sf.hid == null) {
                    sf.clear();
                    sf.hid = sf.hide.defer(100,sf);
                }
            }else {
                sf.clear();
                sf.sid = sf.show.defer(200,sf,[tg]);
            }
        }
    }
    $S.DocMg.register(tip);
    return tip
}();



$S.Cover = function(){
    var m = {
//      bof:null,
        sw:null,
        sh:null,
        container: {},
        cover : function(el,opacity){
//          $S.Cover.bof = Ext.getBody().getStyle('overflow');
            var dd = document.documentElement,db = document.body
            var sw = Ext.isStrict ? dd.scrollWidth : db.scrollWidth;
            var sh = Ext.isStrict ? dd.scrollHeight : db.scrollHeight;
            var screenWidth = Math.max(sw,$S.getViewportWidth());
            var screenHeight = Math.max(sh,$S.getViewportHeight());
            var opt = (opacity) ? 'filter: alpha(opacity='+opacity+');opacity:'+(opacity/100)+';mozopacity:'+(opacity/100) : '';
            var p = '<DIV class="s_cover" style="left:0px;top:0px;width:'+(screenWidth)+'px;height:'+(screenHeight)+'px;'+ opt+'" unselectable="on"></DIV>';
            var cover = Ext.get(Ext.DomHelper.insertFirst(Ext.getBody(),p));
            cover.setStyle('z-index', Ext.fly(el).getStyle('z-index') - 1);
//          Ext.getBody().setStyle('overflow','hidden');
            $S.Cover.container[el.id] = cover;
        },
        uncover : function(el){
            var cover = $S.Cover.container[el.id];
            if(cover) {
                Ext.fly(cover).remove();
                $S.Cover.container[el.id] = null;
                delete $S.Cover.container[el.id];
            }
            var reset = true;
            for(key in $S.Cover.container){
                if($S.Cover.container[key]) {
                    reset = false;  
                    break;
                }
            }
//            if(reset&&$S.Cover.bof)Ext.getBody().setStyle('overflow',$S.Cover.bof);
        },
        resizeCover : function(){
            for(key in $S.Cover.container){
                var cover = $S.Cover.container[key];
                Ext.fly(cover).setStyle('display','none');
            }
            setTimeout(function(){
                var scrollWidth = Ext.isStrict ? document.documentElement.scrollWidth : document.body.scrollWidth;
                var scrollHeight = Ext.isStrict ? document.documentElement.scrollHeight : document.body.scrollHeight;
                var screenWidth = Math.max(scrollWidth,$S.getViewportWidth()) -1;
                var screenHeight = Math.max(scrollHeight,$S.getViewportHeight()) -1;
                for(key in $S.Cover.container){
                    var cover = $S.Cover.container[key];
                    Ext.fly(cover).setWidth(screenWidth);
                    Ext.fly(cover).setHeight(screenHeight);
                    Ext.fly(cover).setStyle('display','');
                }       
            },1)
        }
    }
    return m;
}();
$S.Masker = function(){
    var m = {
        container: {},
        mask : function(el,msg){
            if($S.Masker.container[el.id]){
               return;
            }
            msg = msg||'正在操作...';
            var zindex = 'z-index';
            var el = Ext.get(el);
            var w = el.getWidth();
            var h = el.getHeight();//display:none;
            var p = '<div class="s_mask"  style="left:0px;top:0px;width:'+w+'px;height:'+h+'px;position: absolute;"><div unselectable="on"></div><span style="top:'+(h/2-11)+'px">'+msg+'</span></div>';
            var masker = Ext.get(Ext.DomHelper.insertFirst(el.parent(),p));
            var zi = el.getStyle(zindex) == 'auto' ? 0 : el.getStyle(zindex);
            masker.setStyle(zindex, zi + 1);
            masker.setXY(el.getXY());
            var sp = masker.child('span');
//            var size = $S.TextMetrics.measure(sp,msg);
//            sp.setLeft((w-size.width)/2);
            sp.setLeft((w-sp.getWidth())/2)
            $S.Masker.container[el.id] = masker;
        },
        unmask : function(el){
            var masker = $S.Masker.container[el.id];
            if(masker) {
                Ext.fly(masker).remove();
                $S.Masker.container[el.id] = null;
                delete $S.Masker.container[el.id];
            }
        }
    }
    return m;
}();

$S.evalList = [];
$S.evaling = false;
$S.doEvalScript = function(){
    $S.evaling = true;
    var list = $S.evalList;
    var o = list.shift();
    if(!o) {
        window['__host'] = null;
        $S.evaling = false;
        if($S.loadEvent){
            $S.loadEvent.fire();
            $S.loadEvent = null;
        }
        return;
    }
    var sf = o.sf, html=o.html, loadScripts=o.loadScripts, callback=o.callback, host=o.host,id=o.id;
    var dom = sf.dom;
    
    if(host) window['__host'] = host;
    var links = [];
    var scripts = [];
    var hd = document.getElementsByTagName("head")[0];
    for(var i=0;i<hd.childNodes.length;i++){
        var he = hd.childNodes[i];
        if(he.tagName == 'LINK') {
            links.push(he.href);
        }else if(he.tagName == 'SCRIPT'){
            scripts.push(he.src);
        }
    }
    var jsre = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
    var jsSrcRe = /\ssrc=([\'\"])(.*?)\1/i;
    
    var cssre = /(?:<link([^>]*)?>)((\n|\r|.)*?)/ig;
    var cssHreRe = /\shref=([\'\"])(.*?)\1/i;
    
    var cssm;
    while(cssm = cssre.exec(html)){
        var attrs = cssm[1];
        var srcMatch = attrs ? attrs.match(cssHreRe) : false;
        if(srcMatch && srcMatch[2]){
            var included = false;
            for(var i=0;i<links.length;i++){
                var link = links[i];
                if(link.indexOf(srcMatch[2]) != -1){
                    included = true;
                    break;
                }
            }
            if(!included) {
                var s = document.createElement("link");
                s.type = 'text/css';
                s.rel = 'stylesheet';
                s.href = srcMatch[2];
                hd.appendChild(s);
            }
        }
    }
    var match;
    var jslink = [];
    var jsscript = [];
    while(match = jsre.exec(html)){
        var attrs = match[1];
        var srcMatch = attrs ? attrs.match(jsSrcRe) : false;
        if(srcMatch && srcMatch[2]){
            var included = false;
            for(var i=0;i<scripts.length;i++){
                var script = scripts[i];
                if(script.indexOf(srcMatch[2]) != -1){
                    included = true;
                    break;
                }
            }
            if(!included) {
                jslink[jslink.length] = {
                    src:srcMatch[2],
                    type:'text/javascript'
                }
            } 
        }else if(match[2] && match[2].length > 0){
            jsscript[jsscript.length] = match[2];
        }
    }
    var loaded = 0;
    
    var finishLoad = function(){
        for(j=0,k=jsscript.length;j<k;j++){
            var jst = jsscript[j];
            if(window.execScript) {
                window.execScript(jst);
            } else {
                window.eval(jst);
            }
        }
        var el = document.getElementById(id);
        if(el){Ext.removeNode(el);} 
        Ext.fly(dom).setStyle('display', 'block');
        if(typeof callback == "function"){
            callback();
        }
        $S.doEvalScript();
    }
    
    var continueLoad = function(){
        var js = jslink[loaded];
        var s = document.createElement("script");
        s.src = js.src;
        s.type = js.type;
        s[Ext.isIE ? "onreadystatechange" : "onload"] = onReadOnLoad;
        s["onerror"] = onErrorLoad;
        hd.appendChild(s);        
    }    
    
    var onReadOnLoad = function(){        
        var isready = Ext.isIE ? (!this.readyState || this.readyState == "loaded" || this.readyState == "complete") : true;
        if(isready) {
            loaded ++;
            if(loaded==jslink.length) {
                finishLoad();
            }else{
                continueLoad();
            }
        }
    }
    
    var onErrorLoad = function(evt){
        loaded++;
        alert('无法加载脚本:' + evt.target.src);
        if(loaded==jslink.length) {
            finishLoad();
        }else {
            continueLoad();
        }
    }
    
    if(jslink.length > 0){
        continueLoad();
    } else if(jslink.length ==0) {
        for(j=0,k=jsscript.length;j<k;j++){
            var jst = jsscript[j];
            if(window.execScript) {
               window.execScript(jst);
            } else {
               window.eval(jst);
            }
        }
        var el = document.getElementById(id);
        if(el){Ext.removeNode(el);} 
        Ext.fly(dom).setStyle('display', 'block');
        if(typeof callback == "function"){
                callback();
        }
        $S.doEvalScript();
    } 
}
Ext.Element.prototype.update = function(html, loadScripts, callback,host){
    if(typeof html == "undefined"){
        html = "";
    }
    if(loadScripts !== true){
        this.dom.innerHTML = html;
        if(typeof callback == "function"){
            callback();
        }
        return this;
    }
    
    var id = Ext.id();
    var sf = this;
    var dom = this.dom;
    html += '<span id="' + id + '"></span>';
    Ext.lib.Event.onAvailable(id, function(){
        $S.evalList.push({
            html:html,
            loadScripts:loadScripts,
            callback:callback,
            host:host,
            id:id,
            sf:sf
        });
        if(!$S.evaling)
        $S.doEvalScript() 
    });
    
    Ext.fly(dom).setStyle('display', 'none');
    dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "").replace(/(?:<link.*?>)((\n|\r|.)*?)/ig, "");
    return this;
}

Ext.EventObjectImpl.prototype['isSpecialKey'] = function(){
    var k = this.keyCode;
    return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 || //9-TAB  13-ENTER  40-DOWN  27-ESC
    (k == 16) || (k == 17) ||  //16-SHIFT-L   17-CONTROL-L
    (k >= 18 && k <= 20) ||  //18-ALT-L   19-PAUSE  20-CAP-LOCK
    (k >= 33 && k <= 35) ||
    (k >= 36 && k <= 39) ||
    (k >= 44 && k <= 45);
}
Ext.removeNode = Ext.isIE && !Ext.isIE8 ? function(){
    var d;
    return function(n){
        if(n && n.tagName != 'BODY'){
            (Ext.enableNestedListenerRemoval) ? Ext.EventManager.purgeElement(n, true) : Ext.EventManager.removeAll(n);
            if(!d){
                d = document.createElement('div');
                d.id = '_removenode';
                d.style.cssText = 'position:absolute;display:none;left:-1000px;top:-1000px';
            }
//            d = d || document.createElement('<div id="_removenode" style="position:absolute;display:none;left:-1000px;top:-1000px">');
            if(!d.parentNode)document.body.appendChild(d);
            d.appendChild(n);
            d.innerHTML = '';
            delete Ext.elCache[n.id];
        }
    }
}() : function(n){
    if(n && n.parentNode && n.tagName != 'BODY'){
        (Ext.enableNestedListenerRemoval) ? Ext.EventManager.purgeElement(n, true) : Ext.EventManager.removeAll(n);
        n.parentNode.removeChild(n);
        delete Ext.elCache[n.id];
    }
}
//$S.parseDate = function(str){
//    if(typeof str == 'string'){        
//        var results = str.match(/^ *(\d{4})-(\d{1,2})-(\d{1,2}) *$/);      
//        if(results && results.length>3)      
//            return new Date(parseInt(results[1]),parseInt(results[2],10) -1,parseInt(results[3],10));       
//        results = str.match(/^ *(\d{4})-(\d{1,2})-(\d{1,2}) +(\d{1,2}):(\d{1,2}):(\d{1,2}) *$/);  
//        if(results && results.length>6)      
//        return new Date(parseInt(results[1]),parseInt(results[2],10) -1,parseInt(results[3],10),parseInt(results[4],10),parseInt(results[5],10),parseInt(results[6],10));       
//    }      
//    return null;      
//}
$S.getFunction = function(fn){
    if(!fn) return null;
    if(fn instanceof Function) return fn;
    var rder;
    try{
        if(fn.indexOf('.') != -1){
            var p = fn.substr(0,fn.lastIndexOf('.')),f = fn.substr(fn.lastIndexOf('.')+1);
            if(window.eval) {
               rder = window.eval(p)[f];
            } else if(window.execScript){
               rder = window.execScript(fn)[f];
            }
        }else{
            rder = window[fn];
        }
    } catch(e){
        alert('无法找到' + fn)
    }    
//    if(fn.indexOf('.') != -1){
//        rder = $S[fn.substr(6,fn.length)]
//    }else{
//        rder = window[fn];
//    }
    return rder;
}


$S.formatMoney = function(mnum) {
    mnum = Math.abs(mnum);
    var unitArray = [["元", "万", "亿"], ["仟", "", "拾", "佰"],["零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"]];
    totalarray = new Array();

    totalarray = mnum.toString().split(".");
    if (totalarray.length == 1) {
        totalarray[1] = "00"
    } else if (totalarray[1].length == 1) {
        totalarray[1] += '0';
    }
    integerpart = new Array();
    decimalpart = new Array();
    var strout = "";
    for (var i = 0; i < totalarray[0].length; i++) {
        integerpart[i] = totalarray[0].charAt(i);
    }
    for (var i = 0; i < totalarray[1].length; i++) {
        decimalpart[i] = totalarray[1].charAt(i);
    }
    for (var i = 0; i < integerpart.length; i++) {
        var strTemp = (integerpart.length - i - 1) % 4 == 0
                ? unitArray[0][parseInt((integerpart.length - i) / 4)]
                : (integerpart[i] == 0)
                        ? ""
                        : unitArray[1][((integerpart.length - i) % 4)]
        strout = strout + unitArray[2][integerpart[i]] + strTemp;
    }
    strout = strout.replace(new RegExp(/零+/g), "零");
    strout = strout.replace("零万", "万");
    strout = strout.replace("零亿", "亿");
    strout = strout.replace("零元", "元");
    strout = strout.replace("亿万", "亿");
    var strdec = ""
    if (decimalpart[0] == 0 && decimalpart[1] == 0) {
        strdec = "整";
    } else {
        if (decimalpart[0] == 0) {
            strdec = "零"
        } else {
            strdec = unitArray[2][decimalpart[0]] + '角';
        }
        if (decimalpart[1] != 0) {
            strdec += unitArray[2][decimalpart[1]] + '分';
        }
    }
    strout += strdec;
    if (mnum < 0)
        strout = "负" + strout;
    return strout;
}
/************** Renderer **************/
$S.escapeHtml = function(str){
    if(Ext.isEmpty(str) || !Ext.isString(str)) return str;
    return String(str).replace(/&/gm,'&amp;').replace(/</gm,'&lt;').replace(/>/gm,'&gt;');
}
$S.unescapeHtml = function(str){
    if(Ext.isEmpty(str) || !Ext.isString(str)) return str;
    return String(str).replace(/&amp;/gm,'&').replace(/&lt;/gm,'<').replace(/&gt;/gm,'>');
}
$S.RowNumberRenderer = function(value,record,name){
    if(record && record.ds){
        var ds = record.ds;
        return (ds.currentPage-1)*ds.psize + ds.indexOf(record) + 1;
    }
}
$S.formatDate = function(date){
    return (!date) ? '' : date.format($S.defaultDateFormat);
}
$S.formatDateTime = function(date){
    return (!date) ? '' : date.format('isoDateTime');
}
$S.moneyRenderer = function(v){
    return $S.formatNumber(v,2); 
}
$S.formatNumber = function(value,decimalprecision){
    if(value!==0&&(!value||isNaN(value)))return '';
    if(decimalprecision||decimalprecision===0) value=parseFloat(value).toFixed(decimalprecision);
    var ps = String(value).split('.');
    var sub = (ps.length==2)?'.'+ps[1]:'';
    var whole = ps[0];
    var r = /(\d+)(\d{3})/;
    while (r.test(whole)) {
        whole = whole.replace(r, '$1' + ',' + '$2');
    }
    v = whole + sub;
    return v;   
}
$S.removeNumberFormat = function(rv){
    rv = String(rv||'');
    while (rv.indexOf(',')!=-1) {
        rv = rv.replace(',', '');
    }
    return isNaN(rv) ? parseFloat(rv) : rv;
}

$S.EventManager = Ext.extend(Ext.util.Observable,{
    constructor: function() {
        $S.EventManager.superclass.constructor.call(this);
        this.initEvents();
    },
    initEvents : function(){
        this.addEvents(
            'ajaxerror',
            'ajaxsuccess',
            'ajaxfailed',
            'ajaxstart',
            'ajaxcomplete',
            'valid',
            'timeout'
        );      
    }
});
$S.EM = new $S.EventManager();
$S.regEvent = function(name, hanlder){
    $S.EM.on(name, hanlder);
}
Ext.fly(document.documentElement).on('keydown',function(e,t){
    var tagName = t.tagName.toUpperCase();
    e.keyCode == 8 && ((tagName != 'INPUT' && tagName != 'TEXTAREA') || t.readOnly) && e.stopEvent();
})
//$S.setCookie('_isbox',Ext.isBorderBox);